package bbcom.traversing;

import bbcom.*;
import bbcom.control.BBCoMSettings;
import bbcom.interfaces.IDeployer;
import bbcom.interfaces.IImplementationParser;
import bbcom.interfaces.IPropertiesParser;
import bbcom.messages.BBCoMDeployingException;
import bbcom.messages.BBCoMMessageResource;
import bbcom.messages.BBCoMMessageUtility;
import bbcom.messages.BBCoMTraversingException;
import bbcom.modeling.BBCoMModeling;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Thanh-Trung Pham.
 */
public class BBCoMGlobalTraversing {
    private final String m_strCommandArgsTemplate;
    private final boolean m_isDebuggingEnable;
    private BBCoMModeling m_oBBCoMModeling;

    /**
     * The constructor.
     *
     * @param bbComModeling       the BBCoMModeling to traverse on.
     * @param commandArgsTemplate the command arguments template
     * @param isDebuggingEnable   is debugging enable.
     * @throws BBCoMTraversingException if there is an error.
     */
    public BBCoMGlobalTraversing(BBCoMModeling bbComModeling, String commandArgsTemplate, boolean isDebuggingEnable) throws BBCoMTraversingException {
        if (!bbComModeling.isValid()) {
            throw new BBCoMTraversingException(BBCoMMessageUtility.getResourceMessage(BBCoMMessageResource.BBCOMTRAVERSING_INVALID_BBCOMINSTANCE_TO_TRAVERSE));
        }

        m_oBBCoMModeling = bbComModeling;
        m_isDebuggingEnable = isDebuggingEnable;
        m_strCommandArgsTemplate = commandArgsTemplate;
    }

    /**
     * Traverse the given BBCoM instance within the BBCoM modeling.
     *
     * @throws BBCoMTraversingException if there is an error related to the traversing.
     */
    public Map<String, String> traverse() throws BBCoMTraversingException {
        DeploymentType oDeployment = m_oBBCoMModeling.getDeployment();

        try {
            BBCoMSettings oBBCoMSettings = BBCoMSettings.getInstance();
            IImplementationParser oImplementationParserPlugin = oBBCoMSettings.getImplementationParserPlugin();
            IDeployer oDeployerPlugin = oBBCoMSettings.getDeployerPlugin();

            oDeployerPlugin.setConfigurationSettings(m_oBBCoMModeling.getBaseFolderName());
            IPropertiesParser oPropertiesParserPlugin = oBBCoMSettings.getPropertiesParserPlugin();
            oDeployerPlugin.setPlugins(oPropertiesParserPlugin);

            String strBBCoMInstanceFilename = m_oBBCoMModeling.getBBCoMInstanceFilename();

            DeviceContainerType[] oAllDeviceContainers = m_oBBCoMModeling.getAllDeviceContainers(m_oBBCoMModeling.getDeviceEnvironment(oDeployment));
            for (DeviceContainerType oDeviceContainer : oAllDeviceContainers) {
                PropertiesType oProperties = m_oBBCoMModeling.getProperties(oDeviceContainer);
                oDeployerPlugin.stopJava(oProperties, null);

                oDeployerPlugin.deployBBCoMInstanceFile(oProperties, strBBCoMInstanceFilename);
            }

            List<String> oSortedAllocationNames = BBCoMSharedTraversing.getSortedAllocationNames(m_oBBCoMModeling.getScenario(oDeployment), m_oBBCoMModeling.getAllocationNames(oDeployment));
            for (int i = 0; i < oSortedAllocationNames.size(); i++) {
                String strAllocationName = oSortedAllocationNames.get(i);

                DeviceContainerType oDeviceContainer = m_oBBCoMModeling.getDeviceContainerReferencedByAllocation(oDeployment, strAllocationName);
                PropertiesType oProperties = m_oBBCoMModeling.getProperties(oDeviceContainer);
                DeployableEntityType oDeployableEntity = m_oBBCoMModeling.getDeployableEntityReferencedByAllocation(oDeployment, strAllocationName);

                List<ImplementationType> oImplementations = m_oBBCoMModeling.getImplementations(oDeployableEntity);
                for (int j = 0; j < oImplementations.size(); j++) {
                    List<String> oImplementationDependencies = oImplementationParserPlugin.getImplementationDependencies(oImplementations.get(j));
                    oDeployerPlugin.deployDependencyFiles(oProperties, oImplementationDependencies);
                }
            }

            Map<String, String> oReturnStartJavas = new LinkedHashMap<>();
            for (DeviceContainerType oDeviceContainer : oAllDeviceContainers) {
                PropertiesType oProperties = m_oBBCoMModeling.getProperties(oDeviceContainer);
                String strContainerName = oDeviceContainer.getName();

                String strIPAddress = oPropertiesParserPlugin.getHost(oProperties);

                oReturnStartJavas.put(strContainerName + " (" +strIPAddress +")", oDeployerPlugin.getStartJava(oProperties, String.format(m_strCommandArgsTemplate, strContainerName, strBBCoMInstanceFilename), m_isDebuggingEnable));
            }

            return oReturnStartJavas;
        } catch (Exception oException) {
            //TODO: log into log files.
            oException.printStackTrace();

            throw new BBCoMTraversingException(BBCoMMessageUtility.getResourceMessage(BBCoMMessageResource.BBCOMTRAVERSING_UNEXPECTED_EXCEPTION, oException));
        }
    }

}
